package com.hongawen.threadwork;

import lombok.*;

/**
 * 使用管程法，来实现线程之间的通信问题
 * 角色：生产者、消费者、中间商，比如，顾客去（消费者）KFC购买汉堡，柜台（中间商）查看库存，有则卖给顾客，否则提示厨师（生产者）做汉堡
 * 利用缓冲区
 *
 * @author hongawen
 * @version 1.0.0
 * @date 2021年09月06日 10:10
 */
public class ManageThread {

    public static void main(String[] args) {
        HamburgerBox hamburger = new HamburgerBox();
        Producer producer = new Producer(hamburger);
        Consumer consumer = new Consumer(hamburger);
        new Thread(producer).start();
        new Thread(consumer).start();
    }

}

@Setter
@Getter
@AllArgsConstructor
@NoArgsConstructor
class Hamburger {
    int id ;
}

class HamburgerBox {

    //存放汉堡的箱子
    private Hamburger[] hamburgers = new Hamburger[10];

    //当前汉堡的个数
    private int couts = 0;


    /**
     * 做完一个汉堡，放进箱子
     */
    @SneakyThrows
    public synchronized boolean addHamburger(Hamburger hamburger) {
        //如果汉堡箱子满了。则无法放入，需要等待消费者购买一个
        if (couts == hamburgers.length) {
            this.wait();
        }
        //否则给指定位置放置一个汉堡，并增加count计数
        hamburgers[couts] = hamburger;
        couts++;
        System.out.println("放入第" + hamburger.getId() + "个汉堡成功");
        this.notifyAll();
        return true;
    }


    /**
     * 消费一个汉堡，从箱子拿出一个
     */
    @SneakyThrows
    public synchronized Hamburger getHamburger() {
        //如果汉堡箱子里没有汉堡了，则需要等待厨师做一个汉堡放入
        if (couts == 0) {
            this.wait();
        }
        //否则从箱子里按顺序拿取一个汉堡
        couts--;
        this.notifyAll();
        System.out.println("消费了第" +  hamburgers[couts].getId() + "个汉堡成功");
        return hamburgers[couts];
    }


}

/**
 * 厨师，生产汉堡
 */
class Producer implements Runnable {

    private HamburgerBox hamburgerBox;

    Producer(HamburgerBox hamburger) {
        this.hamburgerBox = hamburger;
    }

    /**
     * 生产汉堡
     */
    @SneakyThrows
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            Hamburger hamburger = new Hamburger(i);
            hamburgerBox.addHamburger(hamburger);
        }
    }
}

/**
 * 顾客，消费汉堡
 */
class Consumer implements Runnable {

    private HamburgerBox hamburgerBox;

    Consumer(HamburgerBox hamburger) {
        this.hamburgerBox = hamburger;
    }

    /**
     * 消费汉堡
     */
    @SneakyThrows
    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            hamburgerBox.getHamburger();
        }
    }
}